package com.bigshen.spring.framework.aop;

import com.bigshen.spring.framework.aop.aspect.AopAdvice;
import com.bigshen.spring.framework.aop.support.AopAdvisedSupport;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;

/**
 * @Author eddy.shen
 * @Date 2020/4/19 15:56
 **/
public class JDKDynamicAOPProxy implements InvocationHandler {

    private AopAdvisedSupport support;

    public JDKDynamicAOPProxy(AopAdvisedSupport support) {
        this.support = support;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        Object result = null;

        // 根据method取到对应通知方法
        Map<String, AopAdvice> adviceMap = support.getMethodCache().get(method);

        try {
            // 前置通知
            if (adviceMap.containsKey("before")) {
                invokeAdvice(adviceMap.get("before"));
            }

            // 业务逻辑
            result = method.invoke(support.getTarget(), args);

            // 后置通知
            if (adviceMap.containsKey("after")) {
                invokeAdvice(adviceMap.get("after"));
            }

        } catch (Exception e) {
            // 异常通知
            if (adviceMap.containsKey("afterThrow")) {
                invokeAdvice(adviceMap.get("afterThrow"));
            }

        }
        return result;
    }

    private void invokeAdvice(AopAdvice aopAdvice) {

        try {
            aopAdvice.getMethod().invoke(aopAdvice.getAspect());
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

    }

    public Object getProxyInstance() {

        return Proxy.newProxyInstance(this.getClass().getClassLoader(), support.getTargetClass().getInterfaces(), this);
    }

}
